package znet

import (
	"errors"
	"fmt"
	"net"
	"zinx/utils"
	"zinx/ziface"
)

// Server /*
/**
IServer 的接口实现,定义一个Serve 的服务器模块
*/
type Server struct {

	//服务器名称
	Name string

	//服务器绑定的ip版本
	IPVersion string

	//服务器监听的ip地址
	IP string

	//f服务器监听的端口
	Port int

	//当前Server由用户绑定的回调router,也就是Server注册的链接对应的处理业务
	MsgHandler ziface.IMsgHandler

	//该server 的连接管理器
	ConnMgr ziface.IConnManager

	//该server创建之后自动调用的hook 函数 -- OnConnStart
	OnConnStart func(conn ziface.IConnection)

	//该server销毁连接之前自动调用的hook 函数 -- OnConnStop
	OnConnStop func(conn ziface.IConnection)
}

//实现IServer 接口

func (s *Server) Start() {
	fmt.Printf("[Zinx GlobalObject] Server Name : %s,Ip : %s,Port : %d\n",
		utils.GlobalObject.Name, utils.GlobalObject.Host, utils.GlobalObject.TcpPort)
	fmt.Printf("[Zinx GlobalObject] Version Name : %s,MaxConn : %d,MaxPackageSize : %d\n",
		utils.GlobalObject.Version, utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPackageSize)
	fmt.Printf("[Start] Server Listenner at Ip :%s ,Port %d, is startring \n", s.IP, s.Port)
	go func() {

		//开启worker 消息队列几工作池
		s.MsgHandler.StartWorkPool()

		//1.获取tcp地址
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resplve tcp addr error :", err)
		}

		//2.监听服务器地址
		listenner, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen ", s.IPVersion, " error", err)
		}
		fmt.Println("start zinx server ", s.Name, "successful listenning")

		//3.阻塞等待客户端链接,处理客户端连接请求

		var cid uint32
		cid = 0
		for {
			//如果有客户端连接,阻塞返回
			conn, err := listenner.AcceptTCP()
			if err != nil {
				fmt.Println("accept error", err)
				continue
			}
			////已经建立客户端连接,处理数据
			//go func() {
			//	for {
			//		buf := make([]byte, 512)
			//		len, err2 := conn.Read(buf)
			//		if err2 != nil {
			//			fmt.Println("recv buf error", err)
			//			continue
			//		}
			//
			//		fmt.Printf("recv buf:%s,len:%d\n", string(buf[:len]), len)
			//		//回显功能
			//		if _, err := conn.Write(buf[:len]); err != nil {
			//			fmt.Println("write back buf error ", err)
			//			continue
			//		}
			//	}
			//}()

			//设置最大连接个数判断,如果超过最大连接,那么关闭次新的连接
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {

				//todo 给客户端响应超出最大连接数,错误包
				fmt.Println("Too Many Connections MaxConn = ", utils.GlobalObject.MaxConn)
				conn.Close()
				continue
			}

			//处理新连接的业务和方法与conn 进行绑定 的到链接模块
			dealConn := NewConnection(s, conn, cid, s.MsgHandler)
			cid++
			go dealConn.Start()
		}
	}()
}

func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	//回显业务
	fmt.Println("[Conn Handle] CallBackToClient ... ")
	if _, err := conn.Write(data[:cnt]); err != nil {
		fmt.Println("write back buf err ", err)
		return errors.New("CallBackToClient error")
	}
	return nil
}

func (s *Server) Stop() {
	//将服务的资源,状态,链接信息进行停止,或回收

	fmt.Println("[Stop] zinx Server name = ", s.Name)
	s.ConnMgr.ClearConn()
}

func (s *Server) Serve() {
	//启动server
	s.Start()

	//TODO 启动服务之后一些扩展业务

	//阻塞
	select {}
}

func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.MsgHandler.AddRouter(msgId, router)
	fmt.Println("add router successful")
}

// NewServer  初始化serve
func NewServer() ziface.IServer {
	s := &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4",
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.TcpPort,
		MsgHandler: NewMsgHandler(),
		ConnMgr:    NewConnManager(),
	}
	return s
}

func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

// SetOnConnStart 注册OnConnStat 钩子函数方法
func (s *Server) SetOnConnStart(hookFunc func(connection ziface.IConnection)) {
	s.OnConnStart = hookFunc
}

// SetOnConnStop 注册OnConnStop 钩子函数方法
func (s *Server) SetOnConnStop(hookFunc func(connection ziface.IConnection)) {
	s.OnConnStop = hookFunc
}

// CallOnConnStart 调用OnConnStat 钩子函数方法
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
	if s.OnConnStart != nil {
		fmt.Println("-----> CallOnConnStart() ....")
		s.OnConnStart(conn)
	}
}

// CallOnConnStop 调用OnConnStop 钩子函数方法
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
	if s.OnConnStop != nil {
		fmt.Println("-----> CallOnConnStop() ....")
		s.OnConnStop(conn)
	}
}
